home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Software Vault: The Gold Collection
/
Software Vault - The Gold Collection (American Databankers) (1993).ISO
/
cdr05
/
xnot12a.zip
/
MATCH.C
< prev
next >
Wrap
C/C++ Source or Header
|
1993-05-20
|
8KB
|
362 lines
#include "jam.h"
/*
* Name: MicroEMACS
* Limited parenthesis matching routines
*
* The hacks in this file implement automatic matching
* of (), [], {}, and other characters. It would be
* better to have a full-blown syntax table, but there's
* enough overhead in the editor as it is.
*
* Since I often edit Scribe code, I've made it possible to
* blink arbitrary characters -- just bind delimiter characters
* to "blink-matching-paren-hack"
*/
#include "def.h"
#include "key.h"
#ifndef WINDOWED
# include "string.h"
#endif
static int rn_(balance,(KCHAR kchar, int flag, int dir)); /* new params, jam */
static VOID rn_(displaymatch,(LINE *lp, int c, int show, int go)); /* JAM */
static BOOL findonly = FALSE;
static LINE *finddotp;
static int finddoto;
/* Balance table. When balance() encounters a character
* that is to be matched, it first searches this table
* for a balancing left-side character. If the character
* is not in the table, the character is balanced by itself.
* This is to allow delimiters in Scribe documents to be matched.
*/
static struct balance {
char left, right;
} bal[] = {
{ '(', ')' },
{ '[', ']' },
{ '{', '}' },
{ '<', '>' },
{ '\0','\0'}
};
static struct balance2 {
char *left, *right;
} bal2[] = {
{ "/*", "*/"},
{ (char *)0, (char *)0}
};
/* find the char which matches this char in parent line
*/
void locatematch(parent, parentdoto, dotp, doto)
LINE *parent;
int parentdoto;
LINE **dotp;
int *doto;
{
LINE *sdotp = curwp->w_dotp;
int sdoto = curwp->w_doto;
*dotp = finddotp = (LINE *)0;
findonly = TRUE;
curwp->w_dotp = parent;
curwp->w_doto = parentdoto;
balance(lgetc(parent, parentdoto), 0, 1);
findonly = FALSE;
if (finddotp)
{
*dotp = finddotp;
*doto = finddoto;
}
curwp->w_dotp = sdotp;
curwp->w_doto = sdoto;
}
/*
* Self-insert character, then show matching character,
* if any. Bound to "blink-matching-paren-command".
*/
showmatch(f, n)
int f, n;
{
register int i, s;
if (f & FFRAND)
return FALSE;
for (i = 0; i < n; i++)
{
/* insert the char
*/
if ((s = selfinsert(FFRAND, 1)) != TRUE)
return s;
if (isCindent() && (key.k_chars[key.k_count-1] == '}'))
alignindent(0, 1); /* self align hack */
/* show the match
*/
if (balance(0, 0, 0) != TRUE) /* unbalanced -- warn user */
ttbeep();
}
return TRUE;
}
showthematch(f, n)
int f, n;
{
register LINE *clp = curwp->w_dotp;
register int cbo = curwp->w_doto;
return balance(lgetc(clp,cbo), 0, 0);
}
gotomatch(f, n)
int f, n;
{
register LINE *clp = curwp->w_dotp;
register int cbo = curwp->w_doto;
return balance(lgetc(clp, cbo), 1, 0);
}
/*
* Search for and display a matching character.
*
* This routine does the real work of searching backward
* for a balancing character. If such a balancing character
* is found, it uses displaymatch() to display the match.
*/
static balance(kchar, stay, defaultdir)
KCHAR kchar;
int stay;
int defaultdir;
{
register LINE *clp;
register int cbo;
int c;
int i;
int rbal, lbal;
int depth;
int dir = -1; /* normally look backward JAM */
int found = FALSE; /* JAM */
if (kchar)
rbal = kchar;
else
rbal = key.k_chars[key.k_count-1];
/* See if there is a matching character -- default to the same
*/
lbal = rbal;
for (i = 0; bal[i].right != '\0'; i++)
if (bal[i].right == (char)rbal)
{
lbal = bal[i].left;
found = TRUE;
break;
}
/* special case of match either direction..
*/
if (kchar && !found) /* didn't fin match in table, reverse */
{ /* and try again */
for (i = 0; bal[i].left != '\0'; i++)
if (bal[i].left == (char)rbal)
{
lbal = bal[i].right;
dir = 1; /* going forward now */
found = TRUE;
break;
}
}
/* control search direction
*/
if (defaultdir)
dir = defaultdir;
/* Move behind the inserted character. We are always guaranteed
* that there is at least one character on the line, since one was
* just self-inserted by blinkparen.
*/
clp = curwp->w_dotp;
cbo = curwp->w_doto - (kchar ? 0 : 1); /* param/behavior change JAM */
depth = 0; /* init nesting depth */
for (;;)
{
if ((cbo == 0) || (cbo == llength(clp)))
{
if ((cbo == 0) && (llength(clp) > 0) && (dir > 0))
; /* front going ->, ok */
else if ((cbo > 0) && (cbo == llength(clp)) && (dir < 0))
; /* end going <- ok */
else
{
clp = (dir > 0 ? lforw(clp) : lback(clp));
if (!clp || (clp == curbp->b_linep))
return (FALSE);
cbo = (dir > 0 ? -1 : llength(clp)+1);
}
}
cbo += dir;
if (cbo == llength(clp)) /* end of line */
c = '\n';
else
c = lgetc(clp,cbo); /* somewhere in middle */
/* Check for a matching character. If still in a nested */
/* level, pop out of it and continue search. This check */
/* is done before the nesting check so single-character */
/* matches will work too. */
if (c == lbal)
{
if (depth == 0)
{
if (findonly)
{
finddotp = clp;
finddoto = cbo;
return (TRUE);
}
displaymatch(clp, cbo, kchar != 0, stay);
return (TRUE);
}
else
depth--;
}
/* Check for another level of nesting. */
if (c == rbal)
depth++;
}
/*NOTREACHED*/
}
/*
* Display matching character.
* Matching characters that are not in the current window
* are displayed in the echo line. If in the current
* window, move dot to the matching character,
* sit there a while, then move back.
*
* I bashed this big time to support finding a match in
* either direction (JAM)
*/
static VOID displaymatch(clp, cbo, show, go)
register LINE *clp;
register int cbo;
register int show, go;
{
register LINE *tlp;
register int tbo;
register int cp;
register int bufo;
register int c;
int inwindow;
char buf[NLINE];
/* Figure out if matching char is in current window by */
/* searching from the top of the window to dot. */
inwindow = FALSE;
for (tlp = curwp->w_linep; tlp != lforw(curwp->w_dotp);
tlp = lforw(tlp))
if (tlp == clp)
inwindow = TRUE;
if ((inwindow == TRUE) || show) /* if force, move anyway */
{
tlp = curwp->w_dotp; /* save current position */
tbo = curwp->w_doto;
curwp->w_dotp = clp; /* move to new position */
curwp->w_doto = cbo;
curwp->w_flag |= WFMOVE;
update(); /* show match */
#ifdef WINDOWED
{
BOOL wasVis = IsCaretVis();
/* Due to windows issues around cursor, it
* is erased while processing an event. Special case
* draw/erase cursor here for feedback.
*/
if (go)
return; /* means move and stay */
SetCaretVis(TRUE);
ttflush(TRUE);
sleep(1); /* wait a bit */
if (!wasVis)
SetCaretVis(FALSE);
ttflush(TRUE);
}
#else
sleep(1); /* wait a bit */
#endif
curwp->w_dotp = tlp; /* return to old position */
curwp->w_doto = tbo;
curwp->w_flag |= WFMOVE;
update();
}
else
{ /* match not in this window so display line in echo area */
bufo = 0;
for (cp = 0; cp < llength(clp); cp++) /* expand tabs */
{
c = lgetc(clp,cp);
if (c != '\t'
#ifdef NOTAB
|| (curbp->b_flag & BFNOTAB)
#endif
)
if(ISCTRL(c))
{
buf[bufo++] = '^';
buf[bufo++] =(char)(CCHR(c));
}
else
buf[bufo++] = (char)c;
else
do {
buf[bufo++] = ' ';
} while (bufo & 7);
}
buf[bufo++] = '\0';
ewprintf("Matches %s",buf);
}
}
char *matchstr(s)
char *s;
{
register int i;
for (i = 0; bal2[i].right; i++)
{
if (strncmp(bal2[i].left, s, strlen(s)) == 0)
return(bal2[i].right);
else if (strncmp(bal2[i].right, s, strlen(s)) == 0)
return(bal2[i].left);
}
return((char *)0);
}
char matchchar(c)
char c;
{
register int i;
for (i = 0; bal[i].right != '\0'; i++)
{
if (bal[i].left == c)
return(bal[i].right);
else if (bal[i].right == c)
return(bal[i].left);
}
return(0);
}